package service

import (
	"boy-go/modules/system/model"
	"boy-go/modules/system/repository"
	"boy-go/modules/system/vo"
	"boy-go/pkg/request"
	"boy-go/pkg/security"
	"boy-go/pkg/xerror"
	"boy-go/pkg/xnum"
	"github.com/jinzhu/copier"
	"gorm.io/gorm"
	"time"
)

func NewSysUserService() SysUserService {
	return &sysUserService{
		SysUserRepo:     repository.NewSysUserRepository(),
		SysUserRoleRepo: repository.NewSysUserRoleRepository(),
		SysDeptRepo:     repository.NewSysDeptRepository(),
		SysRoleRepo:     repository.NewSysRoleRepository(),
	}
}

type sysUserService struct {
	SysUserRepo     *repository.SysUserRepository
	SysUserRoleRepo *repository.SysUserRoleRepository
	SysDeptRepo     *repository.SysDeptRepository
	SysRoleRepo     *repository.SysRoleRepository
}

func (s *sysUserService) GetSysUser(userId int64) *model.SysUser {
	m, err := s.SysUserRepo.GetById(userId)
	if err != nil {
		return nil
	}
	return m
}

// SelectById 根据id获取配置信息
func (s *sysUserService) SelectById(userId int64) (*vo.SysUserModel, error) {
	m, err := s.SysUserRepo.GetById(userId)
	if err != nil {
		return nil, err
	}
	rsp := new(vo.SysUserModel)
	if err := copier.Copy(rsp, m); err != nil {
		return nil, err
	}
	roles, err := s.SysRoleRepo.SelectRoleByUserId(userId)
	if err == nil && roles != nil {
		roleIds := make([]*int64, 0)
		roleModels := make([]*vo.SysRoleModel, 0)
		for _, role := range roles {
			roleIds = append(roleIds, &role.RoleId)
			roleModel := new(vo.SysRoleModel)
			if err := copier.Copy(roleModel, role); err != nil {
				continue
			}
			roleModels = append(roleModels, roleModel)
		}
		rsp.RoleIds = roleIds
		rsp.Roles = roleModels
	}
	return rsp, nil
}

func (s *sysUserService) SelectUserList(req *vo.QuerySysUserReq, pageReq *request.PageRequest) (*vo.ListSysUserRsp, error) {
	list, total, err := s.SysUserRepo.List(req, pageReq)
	if err != nil {
		return nil, err
	}
	deptIds := make([]*int64, 0)
	itemList := make([]*vo.SysUserModel, 0)
	for _, v := range list {
		deptIds = append(deptIds, v.DeptId)
		item := new(vo.SysUserModel)
		if err := copier.Copy(&item, &v); err != nil {
			continue
		}
		itemList = append(itemList, item)
	}
	deptList, err := s.SysDeptRepo.SelectSysDeptByIds(deptIds)
	deptMap := make(map[int64]*model.SysDept)
	for _, v := range deptList {
		deptMap[v.DeptId] = v
	}
	for _, v := range itemList {
		if v.DeptId != nil {
			dept, have := deptMap[*v.DeptId]
			if have && dept != nil {
				deptModel := new(vo.SysDeptModel)
				if err := copier.Copy(&deptModel, dept); err != nil {
					continue
				}
				v.Dept = deptModel
			}
		}
	}
	return &vo.ListSysUserRsp{
		List:  itemList,
		Total: total,
	}, nil
}

func (s *sysUserService) InsertUser(req *vo.AddSysUserReq) (*vo.AddSysUserRsp, error) {
	loginUser := security.GetLoginUser()
	m := new(model.SysUser)
	err := copier.Copy(m, req)
	if err != nil {
		return nil, err
	}
	currentDate := time.Now()
	pass, err := security.EncryptPassword(*req.Password)
	if err != nil {
		return nil, err
	}
	m.Password = pass
	m.CreateBy = &loginUser.UserName
	m.CreateAt = &currentDate
	m.DelFlag = "0"
	if err = s.SysUserRepo.Save(m); err != nil {
		return nil, err
	}
	return &vo.AddSysUserRsp{
		UserId: m.UserId,
	}, nil
}
func _insertUserRoles(tx *gorm.DB, userId int64, roleIds []*int64) error {
	if len(roleIds) > 0 {
		ms := make([]*model.SysUserRole, 0)
		for _, roleId := range roleIds {
			ms = append(ms, &model.SysUserRole{
				UserId: userId,
				RoleId: *roleId,
			})
		}
		//批量保存
		dbErr := tx.Model(&model.SysUserRole{}).CreateInBatches(ms, 200).Error
		return dbErr
	}
	return nil
}
func _insertUserPosts(tx *gorm.DB, userId int64, postIds []*int64) error {
	if len(postIds) > 0 {
		ms := make([]*model.SysUserPost, 0)
		for _, id := range postIds {
			ms = append(ms, &model.SysUserPost{
				UserId: userId,
				PostId: *id,
			})
		}
		//批量保存
		dbErr := tx.Model(&model.SysUserPost{}).CreateInBatches(ms, 200).Error
		return dbErr
	}
	return nil
}
func (s *sysUserService) UpdateUser(req *vo.EditSysUserReq) (*vo.EditSysUserRsp, error) {
	m := new(model.SysUser)
	err := copier.Copy(m, req)
	if err != nil {
		return nil, err
	}
	err = s.SysUserRepo.DB.Transaction(func(tx *gorm.DB) error {
		dbErr := tx.Model(&model.SysUserRole{}).Where("user_id = ?", req.UserId).Delete(&model.SysUserRole{}).Error
		if dbErr != nil {
			return dbErr
		}
		dbErr = _insertUserRoles(tx, req.UserId, req.RoleIds)
		if dbErr != nil {
			return dbErr
		}
		dbErr = tx.Model(&model.SysUserPost{}).Where("user_id = ?", req.UserId).Delete(&model.SysUserPost{}).Error
		dbErr = _insertUserPosts(tx, req.UserId, req.PostIds)
		if dbErr != nil {
			return dbErr
		}
		return tx.Model(&model.SysUser{}).Where("user_id = ?", req.UserId).Omit("user_id").Updates(m).Error
	})
	if err != nil {
		return nil, err
	}
	return &vo.EditSysUserRsp{
		UserId: req.UserId,
	}, nil
}

func (s *sysUserService) DeleteUserById(userId int64) error {
	return s.SysUserRepo.Delete(userId)
}
func (s *sysUserService) DeleteUserByIds(userIds []string) error {
	loginUser := security.GetLoginUser()
	for _, id := range userIds {
		userId := xnum.Str2int64(id)
		err := s.CheckUserAllowed(&userId)
		if err != nil {
			return err
		}
		err = s.CheckUserDataScope(&userId)
		if err != nil {
			return err
		}
	}
	// 添加事务
	err := s.SysUserRepo.DB.Transaction(func(tx *gorm.DB) error {
		dbErr := tx.Model(&model.SysUserRole{}).Where("user_id in ?", userIds).Delete(&model.SysUserRole{}).Error
		if dbErr != nil {
			return dbErr
		}
		dbErr = tx.Model(&model.SysUserPost{}).Where("user_id in ?", userIds).Delete(&model.SysUserPost{}).Error
		if dbErr != nil {
			return dbErr
		}
		dbErr = tx.Model(&model.SysUser{}).Where("user_id in ?", userIds).Updates(map[string]interface{}{
			"del_flag":    "2",
			"update_time": time.Now(),
			"update_by":   loginUser.UserName,
		}).Error
		if dbErr != nil {
			return dbErr
		}
		return nil
	})
	return err
}

// CheckUserAllowed 校验用户是否允许操作
func (s *sysUserService) CheckUserAllowed(userId *int64) error {
	if userId == nil || *userId <= 0 {
		return xerror.NewArgument("用户ID不能为空")
	}
	if model.IsAdmin(userId) {
		return xerror.NewArgument("不允许操作超级管理员用户")
	}
	return nil
}

// CheckUserDataScope 校验用户是否有数据权限
func (s *sysUserService) CheckUserDataScope(userId *int64) error {
	if !model.IsAdmin(userId) {
		userRsp, err := s.SelectUserList(&vo.QuerySysUserReq{
			UserId: userId,
		}, nil)
		if err != nil || len(userRsp.List) <= 0 {
			return xerror.NewArgument("没有操作权限")
		}
	}
	return nil
}

func (s *sysUserService) ResetPwd(req *vo.ResetPwdSysUserReq) error {
	loginUser := security.GetLoginUser()
	pass, err := security.EncryptPassword(*req.Password)
	if err != nil {
		return err
	}
	currentTime := time.Now()
	sysUser := &model.SysUser{
		UserId:   req.UserId,
		Password: pass,
		UpdateBy: &loginUser.UserName,
		UpdateAt: &currentTime,
	}
	err = s.SysUserRepo.Update(sysUser)
	return err
}
func (s *sysUserService) UpdateUserStatus(req *vo.ChangeSysUserReq) error {
	loginUser := security.GetLoginUser()
	currentTime := time.Now()
	sysUser := &model.SysUser{
		UserId:   req.UserId,
		Status:   &req.Status,
		UpdateBy: &loginUser.UserName,
		UpdateAt: &currentTime,
	}
	err := s.SysUserRepo.Update(sysUser)
	return err
}

func (s *sysUserService) CheckUserNameUnique(userId int64, userName *string) bool {
	info, err := s.SysUserRepo.CheckUserNameUnique(userName)
	if err == nil && info != nil && info.UserId != userId {
		return false
	}
	return true
}
func (s *sysUserService) CheckPhoneUnique(userId int64, phone *string) bool {
	info, err := s.SysUserRepo.CheckPhoneUnique(phone)
	if err == nil && info != nil && info.UserId != userId {
		return false
	}
	return true
}
func (s *sysUserService) CheckEmailUnique(userId int64, email *string) bool {
	info, err := s.SysUserRepo.CheckEmailUnique(email)
	if err == nil && info != nil && info.UserId != userId {
		return false
	}
	return true
}
func (s *sysUserService) InsertUserAuth(userId int64, roleIds []*int64) error {
	//添加事务
	err := s.SysUserRoleRepo.DB.Transaction(func(tx *gorm.DB) error {
		dbErr := tx.Model(&model.SysUserRole{}).Where("user_id = ?", userId).Delete(&model.SysUserRole{}).Error
		if dbErr != nil {
			return dbErr
		}
		dbErr = _insertUserRoles(tx, userId, roleIds)
		return dbErr
	})
	return err
}
func (s *sysUserService) SelectAllocatedList(req *vo.QuerySysUserReq) (*vo.ListSysUserRsp, error) {
	pageReq := &request.PageRequest{
		PageNum:  req.PageNum,
		PageSize: req.PageSize,
	}
	sysUsers, total, err := s.SysUserRepo.SelectAllocatedList(req, pageReq)
	if err != nil {
		return nil, err
	}
	itemList := make([]*vo.SysUserModel, 0)
	for _, v := range sysUsers {
		item := new(vo.SysUserModel)
		if err := copier.Copy(&item, v); err != nil {
			continue
		}
		itemList = append(itemList, item)
	}
	return &vo.ListSysUserRsp{
		List:  itemList,
		Total: total,
	}, nil
}
func (s *sysUserService) SelectUnallocatedList(req *vo.QuerySysUserReq) (*vo.ListSysUserRsp, error) {
	pageReq := &request.PageRequest{
		PageNum:  req.PageNum,
		PageSize: req.PageSize,
	}
	sysUsers, total, err := s.SysUserRepo.SelectUnAllocatedList(req, pageReq)
	if err != nil {
		return nil, err
	}
	itemList := make([]*vo.SysUserModel, 0)
	for _, v := range sysUsers {
		item := new(vo.SysUserModel)
		if err := copier.Copy(&item, v); err != nil {
			continue
		}
		itemList = append(itemList, item)
	}
	return &vo.ListSysUserRsp{
		List:  itemList,
		Total: total,
	}, nil
}
